/**
    strfuncs.c - Useful string functions.
    Copyright (C) 2009  Abram Magner

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "strfuncs.h"

//#define STRFUNCS_TEST

#ifdef STRFUNCS_TEST
  #include <assert.h>
#endif

//=============================================================================
// Return the concatenation of a and b and free a.  Note that it's safe to
// call this with NULL arguments.
//=============================================================================
char *mstrconcat (char *a, char *b)
{
  char *result = NULL;

  if (a == NULL && b == NULL) return (NULL);
  if (b == NULL) return (strdup (a));
  if (a == NULL) return (strdup (b));
  result = strconcat (a, b);
  free (a);
  return (result);
}

//=============================================================================
// Return the result of replacing every non-overlapping instance of to in
// src with from and free src.
//=============================================================================
char *mstrsub (char *src, char *from, char *to)
{
  char *result = NULL;
  if (src == NULL) return (NULL);
  result = strsub (src, from, to);
  free (src);
  return (result);
}

//=============================================================================
// Return the result of replacing the first instance of to in src with from
// and free src.
//=============================================================================
char *mstrsub_first (char *src, char *from, char *to)
{
  char *result = NULL;
  if (src == NULL) return (NULL);
  result = strsub_first (src, from, to);
  free (src);
  return (result);
}


//=============================================================================
// Return the concatenation of a and b.
//=============================================================================
char *strconcat (char *a, char *b)
{
  char *result = NULL;
  int rindex = 0, aindex = 0, bindex = 0;
  int alen = 0, blen = 0;

  if (a == NULL || b == NULL) return (NULL);
  alen = strlen (a);
  blen = strlen (b);
  result = malloc (alen + blen + 1);
  if (result == NULL) return (NULL);
  for (aindex = 0; aindex < alen; aindex++, rindex++) result[rindex] = a[aindex];
  for (bindex = 0; bindex <= blen; bindex++, rindex++) result[rindex] = b[bindex];
  return (result);
}

//=============================================================================
// Substitute every non-overlapping occurrence of from in src with to.
//=============================================================================
char *strsub (char *src, char *from, char *to)
{
  char *ptr = NULL, *retval = NULL, *iter = src;
  int srclen = 0, fromlen = 0, tolen = 0, retindex = 0;
  if (src == NULL || from == NULL || to == NULL) return (NULL);

  srclen = strlen (src);
  fromlen = strlen (from);
  tolen = strlen (to);

  if (fromlen < tolen) retval = malloc ((srclen + fromlen) / fromlen * tolen + 1);
  else retval = malloc (srclen + 1);
  if (retval == NULL) return (NULL);

  // iter is the current position in src, ptr is the next occurrence of from in
  // iter, and retindex is the current position in retval.
  while ((ptr = strstr (iter, from)) != NULL)
    {
      int toindex = 0;
      for (; iter < ptr; iter++, retindex++) retval[retindex] = *iter;
      // Copy to into retval.
      for (toindex = 0; toindex < tolen; toindex++, retindex++)
	retval[retindex] = to[toindex];
      iter += fromlen;
    }
  while (iter <= src + srclen)
    {
      retval[retindex] = *iter;
      iter++;
      retindex++;
    }
  return (retval);
}

//=============================================================================
// Substitute the first occurrence of from in src with to.
//=============================================================================
char *strsub_first (char *src, char *from, char *to)
{
  char *ptr = NULL, *retval = NULL, *iter = NULL;
  int srclen = 0, fromlen = 0, tolen = 0, retindex = 0, toindex = 0;
  if (src == NULL || from == NULL || to == NULL) return (NULL);

  srclen = strlen (src);
  fromlen = strlen (from);
  tolen = strlen (to);

  retval = malloc ((srclen - fromlen + tolen) + 1);
  if (retval == NULL) return (NULL);

  ptr = strstr (src, from);
  if (ptr == NULL)
    {
      strcpy (retval, src);
      return (retval);
    }
  iter = src;
  for (; iter < ptr; iter++, retindex++) retval[retindex] = *iter;
  for (toindex = 0; toindex < tolen; toindex++, retindex++)
    retval[retindex] = to[toindex];
  iter += fromlen;
  while (iter <= src + srclen)
    {
      retval[retindex] = *iter;
      iter++;
      retindex++;
    }
  return (retval);
}


//=============================================================================
// Return the substring of str of length length at startindex in a shiny, new
// buffer.
//=============================================================================
char *substring (char *str, int startindex, int length)
{
  char *res = NULL;
  char tempchar = str[startindex + length];
  str[startindex + length] = '\0';
  res = strdup (&str[startindex]);
  str[startindex + length] = tempchar;
  return (res);
}

//=============================================================================
// Return true if pref is a prefix of str.
//=============================================================================
int str_isprefix (char *str, char *pref)
{
  return (strstr (str, pref) == str);
}

#ifdef STRFUNCS_TEST
int main (void)
{
  char *str = NULL;

  // Test mstrconcat.
  str = mstrconcat (str, "brewtus");
  assert (str != NULL && strcmp (str, "brewtus") == 0);
  str = mstrconcat (str, "");
  assert (strcmp (str, "brewtus") == 0);
  str = mstrconcat (str, NULL);
  assert (strcmp (str, "brewtus") == 0);

  assert (str_isprefix ("brewbot", "bre"));
  assert (!str_isprefix ("brewbot", "brea"));
  printf ("strfuncs passed all tests!\n");
  return (0);
}
#endif
